package com.huzz.util.exception;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotSafeException;
import com.huzz.util.body.JsonResult;
import com.huzz.util.body.ResultTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;

/**
 * 统一异常处理
 *
 * @author Huzz
 * @created 2022-04-25
 */
@ControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 处理自定义的业务异常
     *
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(value = BizException.class)
    @ResponseBody
    public JsonResult bizExceptionHandler(HttpServletRequest request, BizException e) {
        logger.error("[业务异常]:\n原因是: {}", e.getErrorMessage());
        return ResultTool.fail(e.getStatusCode(), e.getErrorMessage());
    }

    @ExceptionHandler(value = NotLoginException.class)
    @ResponseBody
    public JsonResult notLoginExceptionHandler(HttpServletRequest request, NotLoginException e) {
        logger.error("[未登录异常]:\n原因是: {}", e.getMessage());
        return ResultTool.fail(e.getCode(), e.getMessage());
    }

    @ExceptionHandler(value = NotSafeException.class)
    @ResponseBody
    public JsonResult NotSafeExceptionHandler(HttpServletRequest request, NotSafeException e) {
        logger.error("[二级认证异常]:\n原因是: {}", "需要进行二级认证");
        return ResultTool.fail(e.getCode(), "需要进行二级认证");
    }

    @ExceptionHandler(value = UtilException.class)
    @ResponseBody
    public JsonResult utilExceptionHandler(HttpServletRequest request, BizException e) {
        logger.error("[工具类异常]:\n原因是: {}", e.getErrorMessage());
        return ResultTool.fail(e.getStatusCode(), e.getErrorMessage());
    }

    /**
     * 参数校验错误
     *
     * @param e
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public JsonResult handlerValidException(Exception e) {
        logger.error("[参数校验失败]:\n详情是: ", e);
        return ResultTool.fail(e.getMessage().substring(e.getMessage().lastIndexOf("[") + 1, e.getMessage().lastIndexOf("]") - 1));
    }

    /**
     * 处理空指针的异常
     *
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(value = NullPointerException.class)
    @ResponseBody
    public JsonResult exceptionHandler(HttpServletRequest request, NullPointerException e) {
        logger.error("[空指针异常]:\n原因是: ", e);
        return ResultTool.fail(e.getMessage());
    }

    /**
     * 参数非法异常
     *
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(value = IllegalArgumentException.class)
    @ResponseBody
    public JsonResult exceptionHandler(HttpServletRequest request, IllegalArgumentException e) {
        logger.error("[参数非法异常]: 方法传递了非法或不适当的参数.\n原因是: ", e);
        return ResultTool.fail(e.getMessage());
    }

    /**
     * 索引超出范围异常
     *
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(value = IndexOutOfBoundsException.class)
    @ResponseBody
    public JsonResult exceptionHandler(HttpServletRequest request, IndexOutOfBoundsException e) {
        logger.error("[索引超出]:\n原因是: ", e);
        return ResultTool.fail(e.getMessage());
    }

    /**
     * 发生了某种 I/O 异常
     *
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(value = IOException.class)
    @ResponseBody
    public JsonResult exceptionHandler(HttpServletRequest request, IOException e) {
        logger.error("[I/O异常]:\n原因是: ", e);
        return ResultTool.fail(e.getMessage());
    }

    /**
     * 文件找不到 异常
     *
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(value = FileNotFoundException.class)
    @ResponseBody
    public JsonResult exceptionHandler(HttpServletRequest request, FileNotFoundException e) {
        logger.error("[文件找不到异常]: 尝试打开由指定路径名表示的文件失败.\n原因是: ", e);
        return ResultTool.fail(e.getMessage());
    }

    /**
     * 找不到类 异常
     *
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(value = ClassNotFoundException.class)
    @ResponseBody
    public JsonResult exceptionHandler(HttpServletRequest request, ClassNotFoundException e) {
        logger.error("[找不到类异常]: 尝试通过其字符串名称加载类时, 找不到具有指定名称的类.\n原因是: ", e);
        return ResultTool.fail(e.getMessage());
    }

    /**
     * 类型转换 异常
     *
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(value = ClassCastException.class)
    @ResponseBody
    public JsonResult exceptionHandler(HttpServletRequest request, ClassCastException e) {
        logger.error("[类型转换异常]:\n原因是: ", e);
        return ResultTool.fail(e.getMessage());
    }

    /**
     * 算术异常 异常
     *
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(value = ArithmeticException.class)
    @ResponseBody
    public JsonResult exceptionHandler(HttpServletRequest request, ArithmeticException e) {
        logger.error("[算术异常]:\n原因是: ", e);
        return ResultTool.fail(e.getMessage());
    }

    /**
     * SQL 异常
     *
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(value = SQLException.class)
    @ResponseBody
    public JsonResult exceptionHandler(HttpServletRequest request, SQLException e) {
        logger.error("[SQL异常]: 发生有关数据库访问错误或其他错误的信息的异常. \n原因是: ", e);
        return ResultTool.fail(e.getMessage());
    }

    /**
     * 处理其他异常
     *
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public JsonResult exceptionHandler(HttpServletRequest request, Exception e) {
        logger.error("[未知异常]:\n原因是: ", e);
        return ResultTool.fail(e.getMessage());
    }

}